import minimist from "minimist";
import readline from "readline";
import fs from "fs";
import finder from "find";
import pLimit from "p-limit";
import GlobToRegExp from "glob-to-regexp";

// 辅助函数：确保正则表达式包含全局匹配标志
function re(pattern, flags = 'g') {
    // 如果传入的是正则表达式，直接使用其标志
    if (pattern instanceof RegExp) {
        flags = pattern.flags;
    }

    // 确保标志中包含全局匹配标志 'g'
    if (!flags.includes('g')) {
        flags += 'g';
    }

    // 返回新的正则表达式
    return new RegExp(pattern, flags);
}

// 搜索信息封装
function createSearchInfoMessage(searchParams) {
    const { directory, pattern, fileFilter, ignoreCase, lineNumbers } = searchParams;
    return `
// 搜索框信息
// 目录: ${directory}
// 模式: ${pattern}
// 文件过滤器: ${fileFilter}
// 是否区分大小写: ${ignoreCase ? "否" : "是"}
// 是否包括行号: ${lineNumbers ? "是" : "否"}
// 执行时间: ${new Date().toLocaleString()}
`;
}

// 搜索结果格式化为美观的JSON
function formatResultsToJson(results, searchInfo = '') {
    // 将结果转换为JSON字符串，并保留格式
    const jsonData = JSON.stringify({ searchInfo, results }, null, 2);
    return jsonData;
}

// 搜索功能，搜索文件内容并匹配正则表达式
function searchContent(file, pattern, includeLineNumbers) {
    return new Promise((resolve) => {
        const matches = [];    // 存储匹配到的内容
        const lines = [];      // 存储匹配到的整行内容
        let lineNumbers = [];  // 存储匹配到的行号（如果需要）
        pattern = re(pattern); // 处理正则表达式

        let lineNumber = 1;    // 行号计数器
        const rl = readline.createInterface({
            input: fs.createReadStream(file) // 创建文件读取流
        });

        rl.on('line', (line) => {
            const result = line.match(pattern); // 尝试匹配当前行
            if (result) {
                matches.push(...result);        // 保存匹配内容
                lines.push(line);              // 保存整行内容
                if (includeLineNumbers) {
                    lineNumbers.push(lineNumber); // 保存行号
                }
            }
            lineNumber++; // 行号递增
        });

        rl.on('close', () => {
            if (matches.length === 0) {
                return resolve(null); // 如果没有匹配项，返回 null
            }
            // 构建结果对象
            const result = {
                filename: file,
                matches,
                lines,
            };
            if (includeLineNumbers) {
                result.lineNumbers = lineNumbers; // 如果需要行号，添加到结果
            }
            resolve(result);
        });
    });
}

// 从 PromiseSettledResult 中提取成功的结果
function getResults(values) {
    return values
        .filter(value => value.status === 'fulfilled' && value.value !== null)
        .map(value => value.value);
}

// 主函数：在目录中查找匹配的文件并搜索内容
function find(pattern, directory, fileFilter = '*', options = {}) {
    return new Promise((resolve, reject) => {
        // 如果 fileFilter 是字符串，转换为正则表达式
        if (typeof fileFilter === 'string') {
            fileFilter = GlobToRegExp(fileFilter, {
                extended: true
            });
        }

        finder.file(fileFilter, directory, (files) => { // 查找匹配的文件
            // console.log("Found files:", files); // 调试：输出找到的文件
            const limit = pLimit(20); // 限制并发数
            const input = files.map(file => 
                limit(() => searchContent(file, pattern, options.includeLineNumbers || false))
            );

            Promise.allSettled(input) // 等待所有搜索完成
                .then(getResults)
                .then(results => {
                    if (options.outputFile) {
                        // 如果指定了输出文件，写入结果
                        const searchInfo = createSearchInfoMessage({
                            directory,
                            pattern: pattern.toString(),
                            fileFilter: fileFilter.toString(),
                            ignoreCase: options.ignoreCase || false,
                            lineNumbers: options.includeLineNumbers || false
                        });

                        fs.writeFile(options.outputFile, formatResultsToJson(results, searchInfo), err => {
                            if (err) reject(err);
                            resolve(results);
                        });
                    } else {
                        resolve(results); // 否则直接返回结果
                    }
                });
        }).error(reject); // 处理查找文件时的错误
    });
}

export default find;

let argv = minimist(process.argv.slice(2));
// console.debug("Input Args: ", argv);

let dir = argv["_"][0];

// 支持的参数
let {
    p: pattern,
    f: fileFilter,
    o: onlyMatching,
    i: ignoreCase,
    l: lineNumbers, // 新增：是否显示行号
    h: helpFlag,
    out: outputFile  // 新增：输出文件
} = argv;

// 显示帮助信息
if (helpFlag) {
    console.log(`
    命令行搜索工具使用指南

    用法:
        node jf.bin.js [目录] [选项]

    选项:
        --pattern, -p          指定要搜索的模式（支持正则表达式）
        --fileFilter, -f       指定要搜索的文件过滤模式（支持glob模式）
        --onlyMatching, -o     只输出匹配的文本内容
        --ignoreCase, -i       忽略大小写
        --lineNumbers, -l      显示匹配内容的行号
        --out                  指定输出结果的文件路径
        --help, -h             显示帮助信息
    `);
    process.exit(0);
}

async function run() {
    if (!pattern) {
        let rl = readline.createInterface({
            input: process.stdin,
            output: process.stdout,
        });

        pattern = await question(rl, "Input complex pattern: ");
        rl.close();
    }

    let flags = ignoreCase ? "ig" : "g";
    const regexPattern = new RegExp(pattern, flags);
    // console.log("Using regex pattern:", regexPattern); // 调试：输出正则表达式

    // 构建选项对象
    const options = {
        includeLineNumbers: lineNumbers === true, // 是否包含行号
        outputFile: outputFile || null, // 输出文件路径
        ignoreCase: ignoreCase // 忽略大小写
    };

    let results = await find(regexPattern, dir, fileFilter, options);

    // 根据参数决定输出内容
    // console.log("Search results:", results); // 调试：输出搜索结果
    for (const r of results) {
        let arr = onlyMatching ? r.matches : r.lines;
        arr.forEach((element, index) => {
            // 如果启用了行号，输出行号和内容
            if (lineNumbers && r.lineNumbers) {
                console.log(`${r.filename}:${r.lineNumbers[index]}: ${element}`);
            } else {
                console.log(element);
            }
        });
    }
}

function question(rl, query) {
    return new Promise((resolve) => {
        rl.question(query, resolve);
    });
}

run();